/*
 * Copyright (c) 2009-2013 EvTech Project
 * All rights reserved.
 * 
 * This file is part of Symbol Matching.
 *
 * Symbol Matching is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version.
 *
 * Symbol Matching is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Symbol Matching.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package fi.honkalampisaatio.reaktiopeli.game;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;

import javax.swing.JPanel;

import fi.honkalampisaatio.game.game.LanguageResource;
import fi.honkalampisaatio.game.logging.GameLogger;
import fi.honkalampisaatio.reaktiopeli.ReaktioPeli;
import fi.honkalampisaatio.reaktiopeli.target.Target;

public class PlayersPanel extends JPanel {

	private static final long serialVersionUID = 1745762943524395761L;
	private ArrayList<Player> playerList;
	private boolean showScore, showTime;
	private ChoicePanel cp;
	private int maxScore;
	private boolean showTimeMeter;
	private BufferedImage correctAnswerImg, wrongAnswerImg;

	public PlayersPanel(ChoicePanel cp)
	{
		playerList = new ArrayList<Player>();
		showScore = true;
		showTimeMeter = false;
		showTime = true;
		maxScore = 0;
		this.cp = cp;
	}
	
	public void setFeedbackImages(BufferedImage correctAnswerImg, BufferedImage wrongAnswerImg)
	{
		this.correctAnswerImg = correctAnswerImg;
		this.wrongAnswerImg = wrongAnswerImg;
	}
	
	public void paintComponent(Graphics g) {
        super.paintComponent(g);       
        Graphics2D g2 = (Graphics2D) g;
        int rowHeight;
        /*
		if(bUseTimeForScore)
		{
        	rowHeight = this.getHeight()/2;
		}
		else
		{
        	rowHeight = this.getHeight();
		}
		*/
    	rowHeight = this.getHeight()/2;
    	if(playerList!=null && playerList.size()>0)
    	{
    		Rectangle2D rc = null;
        	int x = 0;
    		float fontSize = 12;
    		int playerWidth = (int)(this.getWidth()/playerList.size());
        	g2.setFont(getFont().deriveFont(fontSize));
        	if(g2.getFontMetrics().getHeight()!=0) {
        		fontSize = (int)(fontSize * rowHeight/g2.getFontMetrics().getHeight());
            	g2.setFont(getFont().deriveFont(fontSize));
        	}
        	for(int i=0;i<playerList.size();i++) {
        		Player player = playerList.get(i);
            	String scoreStr = player.getPlayerName();
            	if(showScore) {
                	scoreStr = scoreStr+": "+player.getScore();
                	if(maxScore>0)
                	{
                		scoreStr += " / " + maxScore;
                	}
            	}
            	rc = g2.getFontMetrics().getStringBounds(scoreStr, g2);
            	if(rc.getWidth()!=0 && rc.getWidth()>playerWidth*0.9-this.getHeight()) {
            		fontSize = (int)(fontSize * playerWidth*0.9/rc.getWidth()-this.getHeight());
                	g2.setFont(getFont().deriveFont(fontSize));
                	rc = g2.getFontMetrics().getStringBounds(scoreStr, g2);
            	}
        	}
        	for(int i=0;i<playerList.size();i++) {
        		int transferX;
        		Player player = playerList.get(i);
            	String scoreStr = player.getPlayerName();
            	
            	if(showScore) {
                	scoreStr = scoreStr+": "+player.getScore();
                	if(maxScore>0)
                	{
                		scoreStr += " / " + maxScore;
                	}
            	}
            	transferX = 0;//(playerWidth - this.getHeight() - g2.getFontMetrics().stringWidth(scoreStr) - 2)/2;
            	if(wrongAnswerImg!=null && player.getState()==Player.STATE.FAIL) {
            		g2.drawImage(wrongAnswerImg, x+transferX, 0, this.getHeight(), this.getHeight(), null);
            	}
            	else if(correctAnswerImg!=null && player.getState()==Player.STATE.FULL_HIT) {
            		g2.drawImage(correctAnswerImg, x+transferX, 0, this.getHeight(), this.getHeight(), null);
            	}
            	else {
            		boolean buttonPressed = false;
            		Set<Integer> ids = player.getPressedButtonIds();
            		Iterator<Integer> idIterator = ids.iterator();
            		while(idIterator.hasNext()) {
            			BufferedImage buttonImage = cp.getButtonImage(idIterator.next());
            			if(buttonImage!=null) {
            				buttonPressed = true;
                    		g2.drawImage(buttonImage, x+transferX, 0, this.getHeight(), this.getHeight(), null);
            			}
            		}
            		
            		if(!buttonPressed && player.getPlayerImage() != null /*&& 
            				player.getState()==Player.STATE.READY*/)
            		{
            			g2.drawImage(player.getPlayerImage(), x+transferX, 0, 
            					this.getHeight(), this.getHeight(), null);
            		}
            		
            	}
            	g2.drawString(scoreStr, (int)(x+this.getHeight()+2+transferX), g2.getFontMetrics().getMaxAscent());
            	if(showTimeMeter)
            	{
                    int w = (int)(playerWidth*0.9f-this.getHeight());
                    int h = rowHeight-1;
                    int leftW = w;
                    if(player.getMaxRoundTime()>0 && player.getCurrentRoundTime() < player.getMaxRoundTime())
                    {
                    	leftW = w - (int)(w*player.getCurrentRoundTime()/player.getMaxRoundTime());
                    }
                    g2.drawRect(x+this.getHeight(), rowHeight, w, h);
                    g2.fillRect(x+this.getHeight(), rowHeight, leftW, h);
            	}
            	else if(showTime)
            	{
                	String timeStr = player.getGameTime().getTime(LanguageResource.getInstance().get("TIMEFORMAT"));
                	g2.drawString(timeStr, (int)(x+this.getHeight()+2+transferX), rowHeight+g2.getFontMetrics().getMaxAscent());
            	}
        		
            	if(ReaktioPeli.debugUI)
            	{
                	g2.drawRect(x+1, 1, playerWidth-2, this.getHeight()-2);
                	g2.drawRect(x+transferX, 1, this.getHeight(), this.getHeight()-2);
                	g2.drawRect((int)(x+this.getHeight()+2+transferX), 1, 
                			g2.getFontMetrics().stringWidth(scoreStr)-2, this.getHeight()-2);
            	}

            	x=x+playerWidth;
        	}
    	}
	}
	
	public void addPlayer(Player player)
	{
		playerList.add(player);
	}

	public void setShowScore(boolean showScore) 
	{
		this.showScore = showScore; 
	}

	public void showTimeMeter(boolean showTimeMeter) 
	{
		this.showTimeMeter = showTimeMeter; 
	}

	public void setAnswer(int rightAnswer) 
	{
		Iterator<Player> it = playerList.iterator();
		while(it.hasNext()) {
			Player player = it.next();
			player.addTarget(new Target(rightAnswer));
		}
	}

	public int getCountOfFailedPlayers() 
	{
		int count = 0;

		Iterator<Player> it = playerList.iterator();
		while(it.hasNext()) {
			if(it.next().getState()==Player.STATE.FAIL) {
				count++;
			}
		}
		return count;
	}

	public int getCountOfSucceededPlayers() 
	{
		int count = 0;

		Iterator<Player> it = playerList.iterator();
		while(it.hasNext()) {
			if(it.next().getState()==Player.STATE.FULL_HIT) {
				count++;
			}
		}
		return count;
	}
	
	public int getCountOfPlayers() 
	{
		return playerList.size();
	}
	
	public void clearTargets() {
		Iterator<Player> it = playerList.iterator();
		while(it.hasNext()) {
			it.next().clearTargets();
		}
	}


	public void logAllPlayers(String string) {
		Iterator<Player> it = playerList.iterator();
		while(it.hasNext()) {
			GameLogger.getInstance().log(it.next().getPlayerName(), string);
		}
	}
	
	public void clearPlayers(GameRunner gr)
	{
		if(playerList!=null) {
			Iterator<Player> it = playerList.iterator();
			while(it.hasNext()) {
				Player player = it.next();
				player.setScore(0);
				player.clearTargets();
				player.removeTargetEventListener(gr);
				this.removeKeyListener(player);
			}
			playerList.clear();
		}
	}

	public void resetPlayers(GameRunner gr, GamePanel gp)
	{
		if(playerList!=null) {
			Iterator<Player> it = playerList.iterator();
			while(it.hasNext()) {
				Player player = it.next();
				player.setScore(0);
				player.setPlayedTime(0);
				player.clearTargets();
				player.addTargetEventListener(gr);				
				// Added listener to control panel so player can click with mouse from there also..9.12.2012 toni
				cp.addTargetEventListener(gr);
				gp.addKeyListener(player);
			}
		}
	}

	public void setMaxScore(int totalRounds) 
	{
		this.maxScore = totalRounds;
	}

	public void setOmitMistakes(boolean omitMistakes) {
		if(playerList!=null) {
			Iterator<Player> it = playerList.iterator();
			while(it.hasNext()) {
				it.next().setOmitMistakes(omitMistakes);
			}
		}
	}

	/**
	 * 
	 * @param seconds time for milliseconds (shorter is better)
	 */
	public void addPlayedTime(long ms) {
		if(playerList!=null) {
			Iterator<Player> it = playerList.iterator();
			while(it.hasNext()) {
				it.next().addPlayedTime(ms);
			}
		}
		this.repaint();
	}

	public ArrayList<Player> getPlayers() {
		return playerList;
		
	}
	public void setMaxRoundTime(long maxTime) {
		if(playerList!=null) {
			Iterator<Player> it = playerList.iterator();
			while(it.hasNext()) {
				it.next().setMaxRoundTime(maxTime);
			}
		}
	}

	public void newRound() {
		if(playerList!=null) {
			Iterator<Player> it = playerList.iterator();
			while(it.hasNext()) {
				it.next().newRound();
			}
		}
	}

	public void setShowTime(boolean showTime) {
		this.showTime = showTime;
	}
}
